//= require jquery

/**
 * render a string<p>
 *
 *
 * @param data    a object or map, whose attribute is used as template variable
 * @param tag     Support string template as following: '${...}', '#{...}', '{#...#}', '{$...$}'.
 *                  To support multiple tag at same time, use '|' like '${...}|{$...$}'.<br>
 *                  Default value is '#{...}'
 */
String.prototype.render = function (data, tag){
    if(!tag)
        tag = '#{...}';
    tag += '|';
    var reTagStart = tag.replace(/(.*?)(\.{3,})(.*?)\|/g,'($1)|').replace(/[${]/g,'\\$&').replace(/\|$/,'');
    reTagStart = new RegExp(reTagStart,'g');
    reTagStart.compile(reTagStart);
    var reTagEnd = /'|"|\{|\}|>/g;
    reTagEnd.compile(reTagEnd);

    var funcString = "";
    var pos=0;
    for(var mTagStart=null; mTagStart= reTagStart.exec(this); reTagStart.lastIndex=pos){
        funcString += "output+='"+ this.substr(pos, mTagStart.index-pos).replace(/'/g,"\\'").replace(/[\n\r]/g,'\\n') +"';\n";

        //find end tag
        reTagEnd.lastIndex = mTagStart.index+2;
        var mTagEnd=null;
        for(var counter=1;mTagEnd=reTagEnd.exec(this);){
            if(mTagEnd[0]=='{')    //count '{...}'
                counter++;
            else if(mTagEnd[0]=='}'){
                if(mTagStart[0].charAt(0)=='{' && this.charAt(mTagEnd.index-1)==mTagStart[0].charAt(1))
                    break;
                if(--counter==0)
                    break;
            } else if (mTagEnd[0] == '"' || mTagEnd[0] == "'") {
                var reStringEnd=new RegExp('[^\\\\]'+mTagEnd[0], 'g');
                reStringEnd.lastIndex = mTagEnd.index+1;
                var mStringEnd=null;
                if(! (mStringEnd=reStringEnd.exec(this)) )
                    throw 'Not end of string: '+this.substr(mTagEnd.index);
                reTagEnd.lastIndex=mStringEnd.index+2;
            } //skip string
        }
        if(!mTagEnd)
            throw 'End tag not found for position: '+ this.substr(mTagStart.index);

        var code = this.substr(mTagStart.index+2, mTagEnd.index-reTagStart.lastIndex);
        code = code.replace(/&(.{2,4});/g, function(m,m1){  //replace html escaped chars
            var ret = { quot:'"', amp:'&', lt:'<', gt:'>', nbsp:' ' }[m1];
            if(!ret)
                return m;
            return ret;
        });
        if(mTagStart[0].charAt(1)=='{')
            funcString += "output+=("+ code  +");\n";
        else
            funcString += code +";\n";

        pos = mTagEnd.index+1;
    }   //code segments loop
    funcString += "output+='"+ this.substr(pos).replace(/'/g,"\\'").replace(/[\n\r]/g,'\\n') +"';\n";

    funcString='var output = "";\nwith(data){\n__JSCODE__};\n return output;'.replace(/__JSCODE__/,funcString);
    return new Function('data', funcString)(data);
};

/**
 * renderTemplate 客户端对象渲染
 * @param dom: 被渲染对象
 * @param data: 渲染数据，Map或Dom对象
 */
//render a template
//support the following tags by default
function renderTemplate(dom, data){
    //get template string
    var template = $(dom).attr('template');
    if(template==null){
        template=$(dom).html();
        $(dom).attr('template',template);
    }

    //replace variables
    $(dom).html( template.render(data, '#{...}|<#...#>'));

    //show or hide dom node based on their if attribute
    $("[if]").each(function(){
        var e = $(this);
        if(new Function('return '+ e.attr('if') +';')())
            e.show();
        else
            e.hide();
    });
}
